home *** CD-ROM | disk | FTP | other *** search
- static char *sccsid = "@(#)QNX Kermit version 1.0 7/31/85";
- /*
- * K e r m i t File Transfer Utility
- *
- * UNIX Kermit, Columbia University, 1981, 1982, 1983, 1984
- * Bill Catchings, Bob Cattani, Chris Maio, Frank da Cruz,
- * Alan Crosswell, Jeff Damens
- *
- * Also: Jim Guyton, Rand Corporation
- * Walter Underwood, Ford Aerospace
- *
- * usage: kermit c [lbphe line baud par escape-char] to connect
- * kermit s [ddiflbpt line baud par] file ... to send files
- * kermit r [ddiflbpt line baud par] to receive files
- *
- * where c=connect, s=send, r=receive,
- * d=debug, i=image mode, f=no filename conversion, l=tty line,
- * b=baud rate, e=escape char, h=half duplex, t=turnaround char,
- * p=parity, z=log packet transactions.
- *
- * For remote Kermit, format is either:
- * kermit r to receive files
- * or kermit s file ... to send files
- *
- */
-
- /*
- * Modification History:
- *
- *
- * July 1985 Anthony Starks
- *-----------------------------------------------------------------
- * - Added portable break key handling
- *
- * Apr - May 85 Anthony Starks - More QNX work
- *---------------------------------------------------------------------------
- * - Changed turn-around default to be false
- * - Changed debug print tests in rpack() and spack() to
- * check the length not just for NULL
- * - Modified flushinput for QNX (use char_waiting).
- * - Call flushinput() after each packet is received.
- * - Flush after each packet is sent.
- * - Handle QNX end of line (RS) in bufill() and bufemp()
- * - Added baud rate handling by "shelling out" to stty.
- * This is the only portable way (between QNX 1.1x and QNX 1.2)
- * to set the baud rate
- * - Don't flush tty output in parent fork - kercnq (connect module)
- * - Added communication line break signal handling - kerqnx
- *
- * Oct 84 Anthony Starks - Modify for QNX.
- *-----------------------------------------------------------------------------
- * - Use stdio instead of UNIX system calls read, write.
- * - There are separate file pointers for read and write.
- * - Also modified the routines that alter the tty structures.
- * - Note that this initial implementation
- * does not support setting the tty speed.
- * - Removed most of the conditional compilation stuff
- *
- * The files are :
- * kermit.c (this file)
- * kerqnx.c (tty stuff)
- * kercnq.c (the connect command)
- *
- *
- * July 84 Bill Catchings and Jeff Damens - Add necessary commands for
- * communicating with IBM mainframes (t,p,h). Also started to
- * make it more modular. Eventually all conditionals should be
- * removed. After that we will go to a LEX version which will
- * implement all the states needed for a full server version. A
- * command parser is also needed. Limited VAX VMS support was also
- * added (no connect command). Link together KERMIT.C, KER%%%.C
- * (UNX for all present UNIX versions, VMS for VAX VMS) and KERCN%.C
- * (V for Venix on the Pro and U for UNIX this module not used for
- * VMS).
- *
- * May 21 84 - Roy Smith (CUCS), strip parity from checksum in rpack()
- *
- * Oct. 17 Included fixes from Alan Crosswell (CUCCA) for IBM_UTS:
- * - Changed MYEOL character from \n to \r.
- * - Change char to int in bufill so getc would return -1 on
- * EOF instead of 255 (-1 truncated to 8 bits)
- * - Added read() in rpack to eat the EOL character
- * - Added fflush() call in printmsg to force the output
- * NOTE: The last three changes are not conditionally compiled
- * since they should work equally well on any system.
- *
- * Changed Berkeley 4.x conditional compilation flag from
- * UNIX4X to UCB4X.
- * Added support for error packets and cleaned up the printing
- * routines.
- */
-
-
- #include <io.h>
- #include <dev.h>
- #include <timer.h>
- #include <stdio.h> /* Standard QNX definitions */
-
- #ifndef quantum
- #define quantum
- #endif
-
- #define TANDEM 0 /* define it to be nothing if it's unsupported */
-
-
- /* Symbol Definitions */
-
- #define MAXPACKSIZ 94 /* Maximum packet size */
- #define SOH 1 /* Start of header */
-
- #ifndef quantum
- #define CR 13 /* ASCII Carriage Return */
- #define SP 32 /* ASCII space */
- #define DEL 127 /* Delete (rubout) */
- #endif
-
- #define XON 17 /* ASCII XON */
-
- #define MAXTRY 10 /* Times to retry a packet */
- #define MYQUOTE '#' /* Quote character I will use */
- #define MYPAD 0 /* Number of padding characters I will need */
- #define MYPCHAR 0 /* Padding character I need (NULL) */
-
- #define MYTIME 10 /* Seconds after which I should be timed out */
- #define DELAY 20 /* Delay before send-init */
- #define MAXTIM 60 /* Maximum timeout interval */
- #define MINTIM 2 /* Minumum timeout interval */
-
- #define TRUE -1 /* Boolean constants */
- #define FALSE 0
-
- #define DEFESC '^' /* Default escape character for CONNECT */
- #define DEFTRN FALSE /* Default turn around */
- #define DEFLCH FALSE /* Default local echo */
- #define DEFPAR FALSE /* Default parity */
- #define DEFIM FALSE /* Default image mode */
- #define DEFFNC TRUE /* Default file name conversion */
- #define MYEOL '\r' /* End-Of-Line character I need */
- #define EXC_BREAK 0x0002 /* QNX keyboard break */
- #define EXC_ALARM 0x2000 /* QNX alarm exception */
-
-
-
- /* Macro Definitions */
-
- /*
- * tochar: converts a control character to a printable one by adding a space.
- *
- * unchar: undoes tochar.
- *
- * ctl: converts between control characters and printable characters by
- * toggling the control bit (ie. ^A becomes A and A becomes ^A).
- *
- * unpar: turns off the parity bit.
- */
-
- #define tochar(ch) ((ch) + ' ')
- #define unchar(ch) ((ch) - ' ')
- #define ctl(ch) ((ch) ^ 64 )
- #define unpar(ch) ((ch) & 127)
-
-
- /* Global Variables */
-
- int size, /* Size of present data */
- rpsiz, /* Maximum receive packet size */
- spsiz, /* Maximum send packet size */
- pad, /* How much padding to send */
- timint, /* Timeout for foreign host on sends */
- n, /* Packet number */
- numtry, /* Times this packet retried */
- oldtry, /* Times previous packet retried */
- remote, /* -1 means we're a remote kermit */
- image, /* -1 means 8-bit mode */
- parflg, /* TRUE means use parity specified */
- turn, /* TRUE means look for turnaround char (XON) */
- lecho, /* TRUE for locally echo chars in connect mode */
- debug, /* Indicates level of debugging output (0=none) */
- pktdeb, /* TRUE means log all packet to a file */
- filnamcnv, /* -1 means do file name case conversions */
- speed, /* speed to set */
- filecount; /* Number of files left to send */
-
- char state, /* Present state of the automaton */
- cchksum, /* Our (computed) checksum */
- padchar, /* Padding character to send */
- eol, /* End-Of-Line character to send */
- escchr, /* Connect command escape character */
- quote, /* Quote character in incoming data */
- **filelist, /* List of files to be sent */
- *filnam, /* Current file name */
- recpkt[MAXPACKSIZ], /* Receive packet buffer */
- packet[MAXPACKSIZ], /* Packet buffer */
- *ttyname; /* tty name for LINE argument */
-
- FILE *fp, /* File pointer for current disk file */
- *dpfp, /* File pointer for debugging packet log file */
- *ttyr, /* File pointer of tty for input, stdin if remote */
- *ttyw; /* File pointer of tty for output, stdout if remote */
-
- unsigned
- oldttyr,
- oldttyw;
-
-
- /*
- * m a i n
- *
- * Main routine - parse command and options, set up the
- * tty lines, and dispatch to the appropriate routine.
- */
-
- main(argc,argv)
- int argc; /* Character pointers to and count of */
- char **argv; /* command line arguments */
- {
- FILE *ttopen();
- char *cp; /* char pointer */
- int cflg, rflg, sflg; /* flags for CONNECT, RECEIVE, SEND */
- extern int dobreak(); /* Keyboard break function */
- if (argc < 2) usage(); /* Make sure there's a command line */
-
- cp = *++argv; argv++; argc -= 2; /* Set up pointers to args */
-
- /* Initialize these values and hope the first packet will get across OK */
-
- eol = CR; /* EOL for outgoing packets */
- quote = '#'; /* Standard control-quote char "#" */
- pad = 0; /* No padding */
- padchar = NULL; /* Use null if any padding wanted */
-
- speed = cflg = sflg = rflg = 0; /* Turn off all parse flags */
- ttyname = 0;
- remote = TRUE; /* Default is remote mode */
-
- pktdeb = FALSE; /* No packet file debugging */
- turn = DEFTRN; /* Default turnaround */
- lecho = DEFLCH; /* Default local echo */
- parflg = DEFPAR; /* Default parity */
- image = DEFIM; /* Default image mode */
- filnamcnv = DEFFNC; /* Default filename case conversion */
-
- escchr = DEFESC; /* Default escape character */
-
- while ((*cp) != NULL) /* Parse characters in first arg. */
- switch (*cp++)
- {
- case 'c': cflg++; break; /* C = Connect command */
- case 's': sflg++; break; /* S = Send command */
- case 'r': rflg++; break; /* R = Receive command */
-
- case 'd': /* D = Increment debug mode count */
- debug++; break;
-
- case 'f':
- filnamcnv = FALSE; /* F = don't do case conversion */
- break; /* on filenames */
-
- case 'i': /* I = Image (8-bit) mode */
- image = TRUE; break;
-
- case 'h': /* H = Half duplex mode */
- lecho = TRUE; break;
-
- case 't': /* T = Turnaround character (XON) */
- turn = TRUE; break;
-
- case 'l': /* L = specify tty line to use */
- if (argc--) ttyname = *argv++;
- else usage();
- if (debug) printf("Line to remote host is %s\n",ttyname);
- break;
-
- case 'e': /* E = specify escape char */
- if (argc--) escchr = **argv++;
- else usage();
- if (debug) printf("Escape char is \"%c\"\n",escchr);
- break;
-
- case 'p': /* P = specify parity */
- if (argc--)
- switch ((parflg = **argv++))
- {
- case 'n': parflg = FALSE; break; /* None, no parity */
- case 'e':
- case 'm':
- case 'o':
- case 's': break;
- default: parflg = FALSE; usage();
- }
- else usage();
- if (debug) printf("Parity is %c\n",parflg);
- break;
-
- case 'z': /* Use packet file debugging */
- pktdeb = TRUE; break;
-
- /* Move conditional commands to expansion command table */
-
- case 'b': /* B = specify baud rate */
- if (argc--)
- speed = atoi(*argv++);
- else
- usage();
- if (debug)
- printf("Line speed to remote host is %d\n",speed);
- break;
-
- default: usage();
- }
-
- /* Done parsing */
-
- if ((cflg+sflg+rflg) != 1) /* Only one command allowed */
- usage();
-
- if (ttyname) /* If LINE was specified, we */
- { /* operate in local mode */
- ttyr = ttopen(ttyname,"r"); /* Open the tty line for reading */
- ttyw = ttopen(ttyname,"w"); /* open the tty line for writing */
- ttbin(ttyr,&oldttyr); /* Put the tty in binary mode */
- ttbin(ttyw,&oldttyw);
- remote = FALSE; /* Indicate we're in local mode */
- }
- else /* No LINE specified so we operate */
- { /* in remote mode (ie. controlling */
- ttyr = stdin; /* line is used for communication */
- ttyw = stdout;
- ttbin(ttyr, &oldttyr);
- ttbin(ttyw, &oldttyw);
- remote = TRUE;
- }
-
- /* Handle the QNX break (interrupt) exception */
-
- exc_handler(EXC_BREAK, 0, dobreak);
-
- /* All set up, now execute the command that was given. */
-
- if (!remote) printf("%s\n",sccsid+4); /* print version # */
- if (pktdeb) /* Open packet file if requested */
- if ((dpfp=fopen("packet.log","w"))==NULL)
- {
- if (debug) printf("Cannot create packet.log\n");
- pktdeb = FALSE; /* Say file not being used */
- }
-
- if (debug)
- {
- printf("Debugging level = %d\n\n",debug);
- if (pktdeb) printf("Logging all packets to PACKET.LOG\n\n");
-
- if (cflg) printf("Connect command\n\n");
- if (sflg) printf("Send command\n\n");
- if (rflg) printf("Receive command\n\n");
- }
-
- if (cflg) connect(); /* Connect command */
-
- if (sflg) /* Send command */
- {
- if (argc--) filnam = *argv++; /* Get file to send */
- else
- {
- usage(); /* give error */
- }
- fp = NULL; /* Indicate no file open yet */
- filelist = argv; /* Set up the rest of the file list */
- filecount = argc; /* Number of files left to send */
- if (sendsw() == FALSE) /* Send the file(s) */
- printmsg("Send failed."); /* Report failure */
- else /* or */
- printmsg("done."); /* success */
- }
-
- if (rflg) /* Receive command */
- {
- if (recsw() == FALSE) /* Receive the file(s) */
- printmsg("Receive failed.");
- else /* Report failure */
- printmsg("done."); /* or success */
- }
- ttres(ttyr, &oldttyr);
- ttres(ttyw, &oldttyw);
- if (pktdeb) fclose(dpfp); /* Close the debug file */
- }
-
-
- /*
- * s e n d s w
- *
- * Sendsw is the state table switcher for sending files. It loops until
- * either it finishes, or an error is encountered. The routines called
- * by sendsw are responsible for changing the state.
- *
- */
-
- sendsw()
- {
- char sinit(), sfile(), sdata(), seof(), sbreak();
-
- state = 'S'; /* Send initiate is the start state */
- n = 0; /* Initialize message number */
- numtry = 0; /* Say no tries yet */
- if (remote) sleep(MYTIME); /* Sleep to give the guy a chance */
- while(TRUE) /* Do this as long as necessary */
- {
- if (debug) printf("sendsw state: %c\n",state);
- switch(state)
- {
- case 'S': state = sinit(); break; /* Send-Init */
- case 'F': state = sfile(); break; /* Send-File */
- case 'D': state = sdata(); break; /* Send-Data */
- case 'Z': state = seof(); break; /* Send-End-of-File */
- case 'B': state = sbreak(); break; /* Send-Break */
- case 'C': return (TRUE); /* Complete */
- case 'A': return (FALSE); /* "Abort" */
- default: return (FALSE); /* Unknown, fail */
- }
- }
- }
-
-
- /*
- * s i n i t
- *
- * Send Initiate: send this host's parameters and get other side's back.
- */
-
- char sinit()
- {
- int num, len; /* Packet number, length */
-
- if (debug) printf("In sinit retries: %d\n",numtry);
-
- if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
- spar(packet); /* Fill up init info packet */
-
- flushinput(); /* Flush pending input */
-
- spack('S',n,6,packet); /* Send an S packet */
- switch(rpack(&len,&num,recpkt)) /* What was the reply? */
- {
- case 'N': return(state); /* NAK, try it again */
-
- case 'Y':
- if (n != num) /* If wrong ACK, stay in S state */
- return(state); /* and try again */
- rpar(recpkt); /* Get other side's init info */
-
- if (eol == 0) eol = '\n'; /* Check and set defaults */
- if (quote == 0) quote = '#';
-
- numtry = 0; /* Reset try counter */
- n = (n+1)%64; /* Bump packet count */
- return('F'); /* OK, switch state to F */
-
- case 'E': /* Error packet received */
- prerrpkt(recpkt); /* Print it out and */
- return('A'); /* abort */
-
- case FALSE: return(state); /* Receive failure, try again */
-
- default: return('A'); /* Anything else, just "abort" */
- }
- }
-
-
- /*
- * s f i l e
- *
- * Send File Header.
- */
-
- char sfile()
- {
- int num, len; /* Packet number, length */
- char filnam1[50], /* Converted file name */
- *newfilnam, /* Pointer to file name to send */
- *cp; /* char pointer */
-
- if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
-
- if (fp == NULL) /* If not already open, */
- { if (debug) printf(" Opening %s for sending.\n",filnam);
- fp = fopen(filnam,"r"); /* open the file to be sent */
- if (fp == NULL) /* If bad file pointer, give up */
- {
- error("Cannot open file %s",filnam);
- return('A');
- }
- }
-
- strcpy(filnam1, filnam); /* Copy file name */
- newfilnam = cp = filnam1;
- while (*cp != '\0') /* Strip off all leading directory */
- if (*cp++ == '/') /* names (ie. up to the last /). */
- newfilnam = cp;
-
- if (filnamcnv) /* Convert lower case to upper */
- for (cp = newfilnam; *cp != '\0'; cp++)
- if (islower(*cp)) *cp = toupper(*cp);
-
- len = cp - newfilnam; /* Compute length of new filename */
-
- printmsg("Sending %s as %s",filnam,newfilnam);
-
- spack('F',n,len,newfilnam); /* Send an F packet */
- switch(rpack(&len,&num,recpkt)) /* What was the reply? */
- {
- case 'N': /* NAK, just stay in this state, */
- num = (--num<0 ? 63:num); /* unless it's NAK for next packet */
- if (n != num) /* which is just like an ACK for */
- return(state); /* this packet so fall thru to... */
-
- case 'Y': /* ACK */
- if (n != num) return(state); /* If wrong ACK, stay in F state */
- numtry = 0; /* Reset try counter */
- n = (n+1)%64; /* Bump packet count */
- size = bufill(packet); /* Get first data from file */
- return('D'); /* Switch state to D */
-
- case 'E': /* Error packet received */
- prerrpkt(recpkt); /* Print it out and */
- return('A'); /* abort */
-
- case FALSE: return(state); /* Receive failure, stay in F state */
-
- default: return('A'); /* Something else, just "abort" */
- }
- }
-
-
- /*
- * s d a t a
- *
- * Send File Data
- */
-
- char sdata()
- {
- int num, len; /* Packet number, length */
-
- if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
-
- spack('D',n,size,packet); /* Send a D packet */
- switch(rpack(&len,&num,recpkt)) /* What was the reply? */
- {
- case 'N': /* NAK, just stay in this state, */
- num = (--num<0 ? 63:num); /* unless it's NAK for next packet */
- if (n != num) /* which is just like an ACK for */
- return(state); /* this packet so fall thru to... */
-
- case 'Y': /* ACK */
- if (n != num) return(state); /* If wrong ACK, fail */
- numtry = 0; /* Reset try counter */
- n = (n+1)%64; /* Bump packet count */
- if ((size = bufill(packet)) == EOF) /* Get data from file */
- return('Z'); /* If EOF set state to that */
- return('D'); /* Got data, stay in state D */
-
- case 'E': /* Error packet received */
- prerrpkt(recpkt); /* Print it out and */
- return('A'); /* abort */
-
- case FALSE: return(state); /* Receive failure, stay in D */
-
- default: return('A'); /* Anything else, "abort" */
- }
- }
-
-
- /*
- * s e o f
- *
- * Send End-Of-File.
- */
-
- char seof()
- {
- int num, len; /* Packet number, length */
- if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */
-
- spack('Z',n,0,packet); /* Send a 'Z' packet */
- switch(rpack(&len,&num,recpkt)) /* What was the reply? */
- {
- case 'N': /* NAK, just stay in this state, */
- num = (--num<0 ? 63:num); /* unless it's NAK for next packet, */
- if (n != num) /* which is just like an ACK for */
- return(state); /* this packet so fall thru to... */
-
- case 'Y': /* ACK */
- if (n != num) return(state); /* If wrong ACK, hold out */
- numtry = 0; /* Reset try counter */
- n = (n+1)%64; /* and bump packet count */
- if (debug)
- printf(" Closing input file %s, ",filnam);
- fclose(fp); /* Close the input file */
- fp = NULL; /* Set flag indicating no file open */
-
- if (debug) printf("looking for next file...\n");
- if (gnxtfl() == FALSE) /* No more files go? */
- return('B'); /* if not, break, EOT, all done */
- if (debug)
- printf(" New file is %s\n",filnam);
- return('F'); /* More files, switch state to F */
-
- case 'E': /* Error packet received */
- prerrpkt(recpkt); /* Print it out and */
- return('A'); /* abort */
-
- case FALSE: return(state); /* Receive failure, stay in Z */
-
- default: return('A'); /* Something else, "abort" */
- }
- }
-
-
- /*
- * s b r e a k
- *
- * Send Break (EOT)
- */
-
- char sbreak()
- {
- int num, len; /* Packet number, length */
- if (numtry++ > MAXTRY) return('A'); /* If too many tries "abort" */
-
- spack('B',n,0,packet); /* Send a B packet */
- switch (rpack(&len,&num,recpkt)) /* What was the reply? */
- {
- case 'N': /* NAK, just stay in this state, */
- num = (--num<0 ? 63:num); /* unless NAK for previous packet, */
- if (n != num) /* which is just like an ACK for */
- return(state); /* this packet so fall thru to... */
-
- case 'Y': /* ACK */
- if (n != num) return(state); /* If wrong ACK, fail */
- numtry = 0; /* Reset try counter */
- n = (n+1)%64; /* and bump packet count */
- return('C'); /* Switch state to Complete */
-
- case 'E': /* Error packet received */
- prerrpkt(recpkt); /* Print it out and */
- return('A'); /* abort */
-
- case FALSE: return(state); /* Receive failure, stay in B */
-
- default: return ('A'); /* Other, "abort" */
- }
- }
-
-
- /*
- * r e c s w
- *
- * This is the state table switcher for receiving files.
- */
-
- recsw()
- {
- char rinit(), rfile(), rdata(); /* Use these procedures */
-
- state = 'R'; /* Receive-Init is the start state */
- n = 0; /* Initialize message number */
- numtry = 0; /* Say no tries yet */
-
- while(TRUE)
- {
- if (debug) printf(" recsw state: %c\n",state);
- switch(state) /* Do until done */
- {
- case 'R': state = rinit(); break; /* Receive-Init */
- case 'F': state = rfile(); break; /* Receive-File */
- case 'D': state = rdata(); break; /* Receive-Data */
- case 'C': return(TRUE); /* Complete state */
- case 'A': return(FALSE); /* "Abort" state */
- }
- }
- }
-
-
- /*
- * r i n i t
- *
- * Receive Initialization
- */
-
- char rinit()
- {
- int len, num; /* Packet length, number */
-
- if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */
-
- switch(rpack(&len,&num,packet)) /* Get a packet */
- {
- case 'S': /* Send-Init */
- rpar(packet); /* Get the other side's init data */
- spar(packet); /* Fill up packet with my init info */
- spack('Y',n,6,packet); /* ACK with my parameters */
- oldtry = numtry; /* Save old try count */
- numtry = 0; /* Start a new counter */
- n = (n+1)%64; /* Bump packet number, mod 64 */
- return('F'); /* Enter File-Receive state */
-
- case 'E': /* Error packet received */
- prerrpkt(recpkt); /* Print it out and */
- return('A'); /* abort */
-
- case FALSE: /* Didn't get packet */
- spack('N',n,0,0); /* Return a NAK */
- return(state); /* Keep trying */
-
- default: return('A'); /* Some other packet type, "abort" */
- }
- }
-
-
- /*
- * r f i l e
- *
- * Receive File Header
- */
-
- char rfile()
- {
- int num, len; /* Packet number, length */
- char filnam1[50]; /* Holds the converted file name */
-
- if (numtry++ > MAXTRY) return('A'); /* "abort" if too many tries */
-
- switch(rpack(&len,&num,packet)) /* Get a packet */
- {
- case 'S': /* Send-Init, maybe our ACK lost */
- if (oldtry++ > MAXTRY)
- return('A'); /* If too many tries "abort" */
- if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
- { /* Yes, ACK it again with */
- spar(packet); /* our Send-Init parameters */
- spack('Y',num,6,packet);
- numtry = 0; /* Reset try counter */
- return(state); /* Stay in this state */
- }
- else return('A'); /* Not previous packet, "abort" */
-
- case 'Z': /* End-Of-File */
- if (oldtry++ > MAXTRY)
- return('A');
- if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
- { /* Yes, ACK it again. */
- spack('Y',num,0,0);
- numtry = 0;
- return(state); /* Stay in this state */
- }
- else return('A'); /* Not previous packet, "abort" */
-
- case 'F': /* File Header (just what we want) */
- if (num != n) return('A'); /* The packet number must be right */
- strcpy(filnam1, packet); /* Copy the file name */
-
- if (filnamcnv) /* Convert upper case to lower */
- for (filnam=filnam1; *filnam != '\0'; filnam++)
- if (isupper(*filnam)) *filnam = tolower(*filnam);
-
-
- if ((fp=fopen(filnam1,"w"))==NULL) /* Try to open a new file */
- {
- error("Cannot create %s",filnam1); /* Give up if can't */
- return('A');
- }
- else /* OK, give message */
- printmsg("Receiving %s as %s",packet,filnam1);
-
- spack('Y',n,0,0); /* Acknowledge the file header */
- oldtry = numtry; /* Reset try counters */
- numtry = 0; /* ... */
- n = (n+1)%64; /* Bump packet number, mod 64 */
- return('D'); /* Switch to Data state */
-
- case 'B': /* Break transmission (EOT) */
- if (num != n) return ('A'); /* Need right packet number here */
- spack('Y',n,0,0); /* Say OK */
- return('C'); /* Go to complete state */
-
- case 'E': /* Error packet received */
- prerrpkt(recpkt); /* Print it out and */
- return('A'); /* abort */
-
- case FALSE: /* Didn't get packet */
- spack('N',n,0,0); /* Return a NAK */
- return(state); /* Keep trying */
-
- default: return ('A'); /* Some other packet, "abort" */
- }
- }
-
-
- /*
- * r d a t a
- *
- * Receive Data
- */
-
- char rdata()
- {
- int num, len; /* Packet number, length */
- if (numtry++ > MAXTRY) return('A'); /* "abort" if too many tries */
-
- switch(rpack(&len,&num,packet)) /* Get packet */
- {
- case 'D': /* Got Data packet */
- if (num != n) /* Right packet? */
- { /* No */
- if (oldtry++ > MAXTRY)
- return('A'); /* If too many tries, abort */
- if (num == ((n==0) ? 63:n-1)) /* Else check packet number */
- { /* Previous packet again? */
- spack('Y',num,6,packet); /* Yes, re-ACK it */
- numtry = 0; /* Reset try counter */
- return(state); /* Don't write out data! */
- }
- else return('A'); /* sorry, wrong number */
- }
- /* Got data with right packet number */
- bufemp(packet,len); /* Write the data to the file */
- spack('Y',n,0,0); /* Acknowledge the packet */
- oldtry = numtry; /* Reset the try counters */
- numtry = 0; /* ... */
- n = (n+1)%64; /* Bump packet number, mod 64 */
- return('D'); /* Remain in data state */
-
- case 'F': /* Got a File Header */
- if (oldtry++ > MAXTRY)
- return('A'); /* If too many tries, "abort" */
- if (num == ((n==0) ? 63:n-1)) /* Else check packet number */
- { /* It was the previous one */
- spack('Y',num,0,0); /* ACK it again */
- numtry = 0; /* Reset try counter */
- return(state); /* Stay in Data state */
- }
- else return('A'); /* Not previous packet, "abort" */
-
- case 'Z': /* End-Of-File */
- if (num != n) return('A'); /* Must have right packet number */
- spack('Y',n,0,0); /* OK, ACK it. */
- fclose(fp); /* Close the file */
- n = (n+1)%64; /* Bump packet number */
- return('F'); /* Go back to Receive File state */
-
- case 'E': /* Error packet received */
- prerrpkt(recpkt); /* Print it out and */
- return('A'); /* abort */
-
- case FALSE: /* Didn't get packet */
- spack('N',n,0,0); /* Return a NAK */
- return(state); /* Keep trying */
-
- default: return('A'); /* Some other packet, "abort" */
- }
- }
-
-
- /*
- * KERMIT utilities.
- */
-
- dopar (ch)
- char ch;
- {
- int a;
-
- if (!parflg) return(ch); /* false, no parity */
- ch &= 0177;
- switch (parflg)
- {
- case 'm': return(ch | 128); /* Mark */
- case 's': return(ch & 127); /* Space */
- case 'o': ch |= 128; /* Odd */
- case 'e': /* Even */
- a = (ch & 15) ^ ((ch >> 4) & 15);
- a = (a & 3) ^ ((a >> 2) & 3);
- a = (a & 1) ^ ((a >> 1) & 1);
- return((ch & 0177) | (a << 7));
- default: return(ch);
- }
- }
-
-
- clkint() /* Timer interrupt handler */
- {
- reset(); /* Tell rpack to give up */
- }
-
-
- /*
- * s p a c k
- *
- * Send a Packet
- */
-
- spack(type,num,len,data)
- char type, *data;
- int num, len;
- {
- int i; /* Character loop counter */
- char chksum, buffer[100]; /* Checksum, packet buffer */
- register char *bufp; /* Buffer pointer */
-
- if (debug>1) /* Display outgoing packet */
- {
- if (len == 0)
- data[len] = '\0'; /* Null-terminate data to print it */
- printf(" spack type: %c\n",type);
- printf(" num: %d\n",num);
- printf(" len: %d\n",len);
- if (data != NULL)
- printf(" data: \"%s\"\n",data);
- }
-
- bufp = buffer; /* Set up buffer pointer */
- for (i=1; i<=pad; i++)
- putc(padchar,ttyw); /* Issue any padding */
-
- *bufp++ = dopar(SOH); /* Packet marker, ASCII 1 (SOH) */
- *bufp++ = dopar(tochar(len+3)); /* Send the character count */
- chksum = tochar(len+3); /* Initialize the checksum */
- *bufp++ = dopar(tochar(num)); /* Packet number */
- chksum += tochar(num); /* Update checksum */
- *bufp++ = dopar(type); /* Packet type */
- chksum += type; /* Update checksum */
-
- for (i=0; i<len; i++) /* Loop for all data characters */
- {
- *bufp++ = dopar(data[i]); /* Get a character */
- chksum += data[i]; /* Update checksum */
- }
- chksum = (((chksum&0300) >> 6)+chksum)&077; /* Compute final checksum */
- *bufp++ = dopar(tochar(chksum)); /* Put it in the packet */
- *bufp++ = dopar(eol); /* Extra-packet line terminator */
- if (pktdeb)
- {
- *bufp = '\0'; /* Terminate the string */
- fprintf(dpfp,"\nSpack:%s",buffer);
- }
- fwrite(buffer, bufp-buffer, 1 ,ttyw);/* Send the packet */
- fflush(ttyw);
- }
-
- /*
- * r p a c k
- *
- * Read a Packet
- */
-
- rpack(len,num,data)
- int *len, *num; /* Packet length, number */
- char *data; /* Packet data */
- {
- int i, done; /* Data character number, loop exit */
- char t, /* Current input character */
- type, /* Packet type */
- rchksum; /* Checksum received from other host */
- int clkint(); /* Timer interrupt routine */
-
- if ((timint > MAXTIM) || (timint < MINTIM))
- timint = MYTIME;
-
- if (!setexit()) return FALSE; /* Timed out, fail... */
-
- set_timer(TIMER_SET_EXCEPTION, RELATIVE,
- timint * 20, 0, EXC_ALARM, 0 );
- exc_handler(EXC_ALARM, 0, clkint); /* Arm the timeout routine */
-
- if (pktdeb) fprintf(dpfp,"\nRpack:");
- while (inchr() != SOH); /* Wait for packet header */
-
- done = FALSE; /* Got SOH, init loop */
- while (!done) /* Loop to get a packet */
- {
- cchksum = 0;
- if ((t = cinchr()) == SOH) continue;/* Resynchronize if SOH */
- *len = unchar(t)-3; /* Character count */
-
- if ((t = cinchr()) == SOH) continue;/* Resynchronize if SOH */
- *num = unchar(t); /* Packet number */
-
- if ((t = cinchr()) == SOH) continue;/* Resynchronize if SOH */
- type = t; /* Packet type */
-
- /* Put len characters from the packet into the data buffer */
-
- for (i=0; i<*len; i++)
- if ((data[i] = cinchr()) == SOH)
- continue; /* Resynch if SOH */
-
- data[*len] = 0; /* Mark the end of the data */
-
- if ((t = inchr()) == SOH) continue; /* Resynchronize if SOH */
- rchksum = unchar(t); /* Convert to numeric */
- done = TRUE; /* Got checksum, done */
- }
- flushinput(); /* flush to avoid resends */
-
- if (turn) /* User requested trunaround char */
- while (inchr() != XON) /* handling, spin until an XON */
- ;
-
- set_timer(TIMER_CANCEL, RELATIVE, 0); /* Disable the timer interrupt */
- exc_handler(EXC_BREAK, 0, dobreak); /* Re-enable tty break vector */
-
- if (debug>1) /* Display incoming packet */
- {
- if (*len == 0) /* Test for "nothing" */
- data[*len] = '\0'; /* Null-terminate data to print */
- printf(" rpack type: %c\n",type);
- printf(" num: %d\n",*num);
- printf(" len: %d\n",*len);
- if (data != NULL)
- printf(" data: \"%s\"\n",data);
- }
- /* Fold in bits 7,8 to compute */
- cchksum = (((cchksum&0300) >> 6)+cchksum)&077; /* final checksum */
-
- if (cchksum != rchksum) return(FALSE);
-
- return(type); /* All OK, return packet type */
- }
-
-
- /*
- * Get a parity adjusted character from the line, add it to the checksum
- * and return it.
- */
-
- cinchr()
- {
- char ch;
-
- ch = inchr(); /* Get a character */
- cchksum += ch; /* Add to the checksum */
- return(ch);
- }
-
-
- /*
- * Get a character from the line. Do any necessary parity stripping
- * and return the character.
- */
-
- inchr()
- {
- char ch;
-
- ch = getc(ttyr);
- if (pktdeb) /* If debugging put a copy in file */
- fprintf(dpfp,"%c:%03o|",ch,ch);
- if(parflg) ch = unpar(ch); /* Handle parity */
- return(ch);
- }
-
- /*
- * b u f i l l
- *
- * Get a bufferful of data from the file that's being sent.
- * Only control-quoting is done; 8-bit & repeat count prefixes are
- * not handled.
- */
-
- bufill(buffer)
- char buffer[]; /* Buffer */
- {
- int i, /* Loop index */
- t; /* Char read from file */
- char t7; /* 7-bit version of above */
-
- i = 0; /* Init data buffer pointer */
- while((t = getc(fp)) != EOF) /* Get the next character */
- {
- if (t == '\n') t = '\l'; /* Change QNX newline (RS) to LF */
- t7 = unpar(t); /* Get low order 7 bits */
-
- if (t7 < SP || t7==DEL || t7==quote)/* Does this char require */
- { /* special handling? */
- if (t=='\l' && !image)
- { /* Do LF->CRLF mapping if !image */
- buffer[i++] = quote;
- buffer[i++] = ctl('\r');
- }
- buffer[i++] = quote; /* Quote the character */
- if (t7 != quote)
- {
- t = ctl(t); /* and uncontrolify */
- t7 = ctl(t7);
- }
- }
- if (!parflg)
- buffer[i++] = t; /* Deposit the character itself */
- else
- buffer[i++] = t7;
-
- if (i >= spsiz-8) return(i); /* Check length */
- }
- if (i==0) return(EOF); /* Wind up here only on EOF */
- return(i); /* Handle partial buffer */
- }
-
-
- /*
- * b u f e m p
- *
- * Put data from an incoming packet into a file.
- */
-
- bufemp(buffer,len)
- char buffer[]; /* Buffer */
- int len; /* Length */
- {
- int i; /* Counter */
- char t; /* Character holder */
-
- for (i=0; i<len; i++) /* Loop thru the data field */
- {
- t = buffer[i]; /* Get character */
- if (t == MYQUOTE) /* Control quote? */
- { /* Yes */
- t = buffer[++i]; /* Get the quoted character */
- if ((t & 0177) != MYQUOTE) /* Low order bits match quote char? */
- t = ctl(t); /* No, uncontrollify it */
- }
- if (t==CR && !image) /* Don't pass CR if not in image mode */
- continue;
-
- if (t == LF && !image) /* Map LF to QNX newline (RS) if not image */
- t = RS;
- putc(t,fp);
- }
- }
-
-
- /*
- * g n x t f l
- *
- * Get next file in a file group
- */
-
- gnxtfl()
- {
-
- #ifdef VAX_VMS
- return FALSE; /* Wildcarding doesn't work this way on VAX */
- #endif
- if (debug) printf(" gnxtfl: filelist = \"%s\"\n",*filelist);
- filnam = *(filelist++);
- if (filecount-- == 0) return FALSE; /* If no more, fail */
- else return TRUE; /* else succeed */
- }
-
-
- /*
- * s p a r
- *
- * Fill the data array with my send-init parameters
- *
- */
-
- spar(data)
- char data[];
- {
- data[0] = tochar(MAXPACKSIZ); /* Biggest packet I can receive */
- data[1] = tochar(MYTIME); /* When I want to be timed out */
- data[2] = tochar(MYPAD); /* How much padding I need */
- data[3] = ctl(MYPCHAR); /* Padding character I want */
- data[4] = tochar(MYEOL); /* End-Of-Line character I want */
- data[5] = MYQUOTE; /* Control-Quote character I send */
- }
-
-
- /* r p a r
- *
- * Get the other host's send-init parameters
- *
- */
-
- rpar(data)
- char data[];
- {
- spsiz = unchar(data[0]); /* Maximum send packet size */
- timint = unchar(data[1]); /* When I should time out */
- pad = unchar(data[2]); /* Number of pads to send */
- padchar = ctl(data[3]); /* Padding character to send */
- eol = unchar(data[4]); /* EOL character I must send */
- quote = data[5]; /* Incoming data quote character */
- }
-
-
- /*
- * f l u s h i n p u t
- *
- * Dump all pending input to clear stacked up NACK's.
- */
-
- flushinput()
- {
- long int count; /* Number of bytes ready to read */
- long int i; /* Number of bytes to read in loop */
- count = (long)char_waiting(ttyr); /* See how many bytes pending read */
- if (pktdeb)
- fprintf(dpfp,"%d characters waiting\n", count);
- if (!count) return; /* If zero, then no input to flush */
-
- while (count) /* Loop till all are flushed */
- {
- i = (count<sizeof(recpkt)) ? /* Read min of count and size of */
- count : sizeof(recpkt); /* the read buffer */
- fread(recpkt, i, 1, ttyr); /* Read a bunch */
- count -= i; /* Subtract from amount to read */
- }
- }
-
-
- /*
- * Kermit printing routines:
- *
- * usage - print command line options showing proper syntax
- * printmsg - like printf with "Kermit: " prepended
- * error - like printmsg if local kermit; sends a error packet if remote
- * prerrpkt - print contents of error packet received from remote host
- */
-
- /*
- * u s a g e
- *
- * Print summary of usage info and quit
- */
-
- usage()
- {
- printf("Usage: kermit c[hlbep line baud esc.char par] (connect mode)\n");
- printf("or: kermit s[tdiflbp line baud par] file ... (send mode)\n");
- printf("or: kermit r[tdiflbp line baud par] (receive mode)\n");
- exit(1);
- }
-
- /*
- * p r i n t m s g
- *
- * Print message on standard output if not remote.
- */
-
- /*VARARGS1*/
- printmsg(fmt, a1, a2, a3, a4, a5)
- char *fmt;
- {
- if (!remote)
- {
- printf("Kermit: ");
- printf(fmt,a1,a2,a3,a4,a5);
- printf("\n");
- fflush(stdout); /* force output (UTS needs it) */
- }
- }
-
- /*
- * e r r o r
- *
- * Print error message.
- *
- * If local, print error message with printmsg.
- * If remote, send an error packet with the message.
- */
-
- /*VARARGS1*/
- error(fmt, a1, a2, a3, a4, a5)
- char *fmt;
- {
- char msg[80];
- int len;
-
- if (remote)
- {
- sprintf(msg,fmt,a1,a2,a3,a4,a5); /* Make it a string */
- len = strlen(msg);
- spack('E',n,len,msg); /* Send the error packet */
- }
- else printmsg(fmt, a1, a2, a3, a4, a5);
- }
-
- /*
- * p r e r r p k t
- *
- * Print contents of error packet received from remote host.
- */
- prerrpkt(msg)
- char *msg;
- {
- printf("Kermit aborting with this error from remote host:\n%s\n",msg);
- }
-
- /*
- * d o b r e a k
- *
- * Handle tty breaks from micro
- */
- dobreak()
- {
- fprintf(stderr,"\nKermit-QNX terminated%c\n",007);
- ttres(ttyr,&oldttyr);
- ttres(ttyw,&oldttyw);
- if (pktdeb)
- fclose(dpfp);
- exit(1);
- }
-